# 指定使用的 cmake 的最低版本，可选，非必须，如果不加可能会有警告
cmake_minimum_required(VERSION 2.8)

# 定义工程名称，并可指定工程的版本、工程描述、web主页地址、支持的语言（默认情况支持所有语言），如果不需要这些都是可以忽略的，只需要指定出工程名字即可。
project(calc)

# g++ *.cpp -std=c++11 -o app
# 相当于在g++命令加上 -std=c++11 选项
set(CMAKE_CXX_STANDARD 11)

# 在CMake中指定可执行程序输出的路径，也对应一个宏，叫做EXECUTABLE_OUTPUT_PATH，它的值还是通过set命令进行设置，这个路径不需要自己创建，cmake会自动创建
# set(HOME /home/cpp-linux/test01/04cmake01)
set(EXECUTABLE_OUTPUT_PATH $ENV{EXECUTABLE_OUTPUT_PATH})  # $ENV{EXECUTABLE_OUTPUT_PATH} 引用环境变量

# PROJECT_SOURCE_DIR变量解释
# PROJECT_SOURCE_DIR是CMake内置变量之一，它代表当前项目根目录的路径。当使用project命令指定项目名称时，
# CMake会自动设置PROJECT_SOURCE_DIR的默认值为项目根目录的路径（CMakeLists.txt所在的路径）。
# 如果你使用的是子目录CMakeLists.txt，那么PROJECT_SOURCE_DIR将会是子目录的路径。
# 特别注意：是在project (broadcast)调用后有效,否则为空字符串
message("PROJECT_SOURCE_DIR=${PROJECT_SOURCE_DIR}")
message("CMAKE_CURRENT_SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR}")


# 搜索文件，设置源代码文件路径，其实也是设置一个变量，其值就是一个字符串，包含要编译的源文件
# 方式一（不推荐）：aux_source_directory(.. ..)  
# 如果一个项目里边的源文件很多，在编写CMakeLists.txt文件的时候不可能将项目目录的各个文件一一罗列出来，这样太麻烦也不现实。
# 所以，在CMake中为我们提供了搜索文件的命令，可以使用aux_source_directory命令或者file命令。
# aux_source_directory(< dir > < variable >)
# aux_source_directory(src SRC_LIST)

# 方式二（推荐）：file(.. .. ..)
# 在CMake中为我们提供了搜索文件的命令，他就是file（当然，除了搜索以外通过 file 还可以做其他事情）。
# file(GLOB/GLOB_RECURSE 变量名 要搜索的文件路径和文件类型)
# GLOB: 将指定目录下搜索到的满足条件的所有文件名生成一个列表，并将其存储到变量中。
# GLOB_RECURSE：递归搜索指定目录，将搜索到的满足条件的文件名生成一个列表，并将其存储到变量中。
# CMAKE_CURRENT_SOURCE_DIR 宏表示当前访问的 CMakeLists.txt 文件所在的路径
# 关于要搜索的文件路径和类型可加双引号，也可不加: file(GLOB MAIN_SRC "${CMAKE_CURRENT_SRC_DIR}/src/*.cpp")
file(GLOB MAIN_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)

message("MAIN_SRC=${MAIN_SRC}")

# 设置头文件搜索
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)

# 指定库文件输出的路径（注意，要放在add_library()之前）
# 方式1 - 适用于动态库
# 对于生成的库文件来说和可执行程序一样都可以指定输出路径。
# 由于在Linux下生成的动态库默认是有执行权限的，所以可以按照生成可执行程序的方式去指定它生成的目录，即EXECUTABLE_OUTPUT_PATH，上面已设置。

# 方式2 - 都适用
# 由于在Linux下生成的静态库默认不具有可执行权限，所以在指定静态库生成的路径的时候就不能使用EXECUTABLE_OUTPUT_PATH宏了，
# 而应该使用LIBRARY_OUTPUT_PATH，这个宏对应静态库文件和动态库文件都适用。
set(LIBRARY_OUTPUT_PATH $ENV{CMAKE_CURRENT_SOURCE_DIR}/lib)

# 制作静态库
# 在cmake中，如果要制作静态库，需要使用的命令如下：
# add_library(库名称 STATIC 源文件1 [源文件2] ...) 
# 在Linux中，静态库名字分为三部分：lib+库名字+.a，此处只需要指定出库的名字就可以了，另外两部分在生成该文件的时候会自动填充。
add_library(calc_static STATIC ${MAIN_SRC})

# 制作动态库
# 在cmake中，如果要制作动态库，需要使用的命令如下：
# add_library(库名称 SHARED 源文件1 [源文件2] ...) 
# 在Linux中，动态库名字分为三部分：lib+库名字+.so，此处只需要指定出库的名字就可以了，另外两部分在生成该文件的时候会自动填充。
add_library(calc_dynamic SHARED ${MAIN_SRC})


# 链接静态库（需要放在add_executable()之前）
# 先指定静态库所在路径（默认会从环境变量LD_LIBRARY_PATH中搜索，但是自定义的库需要手动指定搜索路径）
# link_directories(${LIBRARY_OUTPUT_PATH})
# 然后链接指定名称的静态库
# link_libraries(calc_static)


# 定义工程会生成一个可执行程序
# add_executable(app main.cpp ${MAIN_SRC})  # 制作完静态库/动态库之后，就把库中的源文件编译进来了，而是链接库
add_executable(app main.cpp)


# 链接动态库（需要放在add_executable()之后）
# 也是要先指定动态库搜索路径
# link_directories(${LIBRARY_OUTPUT_PATH})
# 然后再链接指定名称的动态库，在cmake中链接动态库的命令如下:
# target_link_libraries(
#     <target> 
#     <PRIVATE|PUBLIC|INTERFACE> <item>... 
#     [<PRIVATE|PUBLIC|INTERFACE> <item>...]...)
# 用于指定一个目标（如可执行文件或库）在编译时需要链接哪些库。它支持指定库的名称、路径以及链接库的顺序。
# target：指定要加载的库的文件的名字
#       该文件可能是一个源文件
#       该文件可能是一个动态库/静态库文件
#       该文件可能是一个可执行文件
# PRIVATE|PUBLIC|INTERFACE：动态库的访问权限，默认为PUBLIC
# 如果各个动态库之间没有依赖关系，无需做任何设置，三者没有没有区别，一般无需指定，使用默认的 PUBLIC 即可。
# 动态库的链接具有传递性，如果动态库 A 链接了动态库B、C，动态库D链接了动态库A，此时动态库D相当于也链接了动态库B、C，并可以使用动态库B、C中定义的方法。
# target_link_libraries(A B C)
# target_link_libraries(D A)
#       PUBLIC：在public后面的库会被Link到前面的target中，并且里面的符号也会被导出，提供给第三方使用。
#       PRIVATE：在private后面的库仅被link到前面的target中，并且终结掉，第三方不能感知你调了啥库
#       INTERFACE：在interface后面引入的库不会被链接到前面的target中，只会导出符号。
# 链接系统动态库
# 动态库的链接和静态库是完全不同的：
# 静态库会在生成可执行程序的链接阶段被打包到可执行程序中，所以可执行程序启动，静态库就被加载到内存中了。
# 动态库在生成可执行程序的链接阶段不会被打包到可执行程序中，当可执行程序被启动并且调用了动态库中的函数的时候，动态库才会被加载到内存
# 因此，在cmake中指定要链接的动态库的时候，应该将命令写到生成了可执行文件之后
target_link_libraries(app PUBLIC calc_dynamic)








